use crate::cli::project::bind::project_bind;
use crate::cli::project::build::project_build;
use crate::cli::project::config::project_config;
use crate::cli::project::debug::project_debug;
use crate::cli::project::delete::project_delete;
use crate::cli::project::download::project_download;
use crate::cli::project::init::project_init;
use crate::cli::project::list::project_list;
use clap::Subcommand;
use regex::Regex;

#[derive(Subcommand, Debug, Clone)]
pub enum ProjectSubcommand {
    /// 项目初始化操作。
    Init {
        /// 项目名称(必选)。
        #[arg(short, long, value_parser=check_name)]
        name: String,
        ///项目类型(必选)
        /// 支持的类型为：1. 应用项目：app；
        ///             2. 静态库项目：static；
        ///             3. 动态库项目：share。
        #[arg(short='t', long, value_parser=check_project_type)]
        project_type: String,
        ///目标操作系统类型(必选);
        /// 支持的操作类型有：1. 硬实时操作系统：rt；
        ///                2. 软实时操作系统：nort。
        #[arg(short, long, value_parser = check_os_type)]
        os: String,
        ///IDE平台规范(可选)；
        /// 支持的规范有：1. vscode, 2. eclipse。
        /// 若未指定，则默认为vscode平台。
        #[arg(short, long, default_value="vscode", value_parser=check_ide_type)]
        ide: Option<String>,
        ///项目目录(可选)；
        ///若未指定，则默认为当前执行目录。
        #[arg(short, long, default_value = "./")]
        dir: Option<String>,
        ///编程语言(可选)；
        ///支持的编程语言为：1. c;
        ///               2. cpp;
        /// 若未指定，则默认为c语言。
        #[arg(short, long, default_value = "c", value_parser = check_lang_type)]
        lang: Option<String>,
        ///目标机体系架构(可选);
        ///支持的体系架构有：1. arm;
        ///               2. arm64;
        ///若未指定，则默认为【arm】架构。
        #[arg(short, long, default_value = "arm", value_parser = check_arch_type)]
        arch: Option<String>,
    },
    /// 项目构建类操作。
    Build {
        /// 项目清理(可选)
        #[arg(short, long)]
        clean: Option<bool>,
        ///项目重建(可选)。
        #[arg(short = 't', long)]
        rebuild: Option<bool>,
        ///项目所在的绝对路径(可选)；
        ///若未指定，则默认为当前执行目录。
        #[arg(short, long, default_value = "./")]
        dir: Option<String>,
        ///仅执行生成器(可选)；
        ///若未指定，则默认为全构建。
        #[arg(short, long)]
        only_exec_generator: Option<String>,
    },
    /// 项目远程下载类操作
    Download {
        ///扫描局域网内的可用RTOS(可选)。
        /// 注：1. 该参数仅针对硬实时操作系统。
        #[arg(short, long)]
        scan: Option<bool>,
        ///项目所在的绝对路径(可选)；
        /// 若未指定，则默认为当前执行目录。
        #[arg(short, long)]
        dir: Option<String>,
        ///重置下载配置(可选)；
        /// 注：1. 该参数仅针对硬实时操作系统。
        #[arg(short, long)]
        reset: Option<bool>,
        ///执行运行模式(可选);
        /// 若未指定，则默认为仅下载模式。
        #[arg(short = 'R', long)]
        run: Option<bool>,
        ///使用SCP执行下载/运行(可选);
        /// 注：1. 在非免密模式下，参数格式为：${TargetIP}::{TargetPort}::{Username}::{Password};
        ///    2. 在免密模式下，参数格式为：${TargetIP}::{TargetPort}::{Username};
        ///    3. 该参数仅针对软实时操作系统。
        #[arg(short = 'S', long)]
        scp: Option<String>,
        ///文件下载的远程存放目录(可选);
        ///若未指定，则默认为远程目标机上的：/root目录
        /// 注： 1. 该参数仅针对软实时操作系统。
        #[arg(long)]
        remote_dir: Option<String>,
        ///下载时同时下载关联的库(可选);
        ///若未指定，则仅下载应用。
        #[arg(short, long)]
        with_lib: Option<bool>,
    },
    /// 项目列表类操作
    List {
        ///以json格式输出项目信息(可选)。
        ///若未指定，默认以键值对格式输出
        #[arg(short, long)]
        json: Option<bool>,
        ///指定项目名称(可选)。
        #[arg(short, long)]
        name: Option<String>,
        ///目标机体系架构(可选);
        ///支持的体系架构有：1. arm;
        ///               2. arm64;
        #[arg(short, long, value_parser = check_arch_type)]
        arch: Option<String>,
        ///编程语言(可选)；
        ///支持的编程语言为：1. c;
        ///               2. cpp;
        #[arg(short, long, value_parser = check_lang_type)]
        lang: Option<String>,
        ///指定项目的类型，多个类型用逗号分隔(可选)
        ///支持的类型为: 1. 应用项目：app；
        ///            2. 静态库项目：static；
        ///            3. 动态库项目：share。
        #[arg(short, long, value_parser = check_project_type)]
        project_type: Option<String>,
        ///指定项目的操作系统类型，多个类型用逗号分隔(可选)
        ///支持的操作类型有: 1. 硬实时操作系统：rt；
        ///               2. 软实时操作系统：nort。
        #[arg(short, long, value_parser = check_os_type)]
        os: Option<String>,
    },
    /// 项目删除类操作
    Delete {
        ///项目ID(必选)。
        ///项目ID可通过project list命令获取
        #[arg(short, long)]
        id: String,
    },
    /// 项目调试类操作
    Debug {
        ///基于扫描类的调试启动操作(可选)；
        ///该场景仅针对RTOS。
        #[arg[short, long]]
        scan: Option<bool>,
        ///项目所在的绝对路径(可选)；
        ///若未指定，则默认为当前执行目录。
        #[arg(short, long, default_value = "./")]
        dir: Option<String>,
        ///是否启动本地调试客户端(可选)；
        ///若未指定，则默认不启动本地调试客户端。
        ///注：若未指定该参数，则命令行返回远程调试端口，该端口可由调用者远程连接调试服务。
        #[arg(short, long)]
        enable_local_cli: Option<bool>,
        ///显示调试器路径(可选);
        ///注：需通过【--dir】参数指定项目路径，若未指定，则默认为当前执行目录。
        #[arg[short, long]]
        show_debugger_path: Option<bool>,
    },
    /// 项目配置类操作
    Config {},
    /// 项目绑定类操作
    Bind {
        ///项目目录(必选)。
        #[arg[short, long]]
        project_dir: String,
        ///软件包名称(必选)。
        #[arg[short='P', long]]
        pkg_name: String,
    },
}

fn check_name(name: &str) -> Result<String, String> {
    if name.len() > 32 {
        return Err("项目名称不能超过32个字符".to_string());
    }
    let regex = Regex::new(r"^[a-zA-Z0-9_-]+$").unwrap();
    if !regex.is_match(&name) {
        return Err("项目名不能包含特殊字符".to_string());
    }
    Ok(name.to_string())
}

fn check_project_type(init_type: &str) -> Result<String, String> {
    match init_type {
        "app" => Ok("app".to_string()),
        "static" => Ok("static".to_string()),
        "share" => Ok("share".to_string()),
        _ => Err("不支持的项目类型".to_string()),
    }
}

fn check_os_type(os_type: &str) -> Result<String, String> {
    match os_type {
        "rt" => Ok("rt".to_string()),
        "nort" => Ok("nort".to_string()),
        _ => Err("不支持的操作系统类型".to_string()),
    }
}

fn check_ide_type(ide_type: &str) -> Result<String, String> {
    match ide_type {
        "vscode" => Ok("vscode".to_string()),
        "eclipse" => Ok("eclipse".to_string()),
        _ => Err("不支持的IDE类型".to_string()),
    }
}

fn check_lang_type(lang_type: &str) -> Result<String, String> {
    match lang_type {
        "c" => Ok("c".to_string()),
        "cpp" => Ok("cpp".to_string()),
        _ => Err("不支持的编程语言类型".to_string()),
    }
}

fn check_arch_type(arch_type: &str) -> Result<String, String> {
    match arch_type {
        "arm" => Ok("arm".to_string()),
        "arm64" => Ok("arm64".to_string()),
        _ => Err("不支持的体系架构类型".to_string()),
    }
}

pub fn project_run(cmd: ProjectSubcommand) {
    match cmd {
        ProjectSubcommand::Init {
            name,
            project_type,
            os,
            ide,
            dir,
            lang,
            arch,
        } => project_init(name, project_type, os, ide, dir, lang, arch),
        ProjectSubcommand::Build {
            clean,
            rebuild,
            dir,
            only_exec_generator,
        } => project_build(clean, rebuild, dir, only_exec_generator),
        ProjectSubcommand::Download {
            scan,
            dir,
            reset,
            run,
            scp,
            remote_dir,
            with_lib,
        } => project_download(scan, dir, reset, run, scp, remote_dir, with_lib),
        ProjectSubcommand::List {
            json,
            name,
            arch,
            lang,
            project_type,
            os,
        } => project_list(json, name, arch, lang, project_type, os),
        ProjectSubcommand::Delete { id } => project_delete(id),
        ProjectSubcommand::Debug {
            scan,
            dir,
            enable_local_cli,
            show_debugger_path,
        } => project_debug(scan, dir, enable_local_cli, show_debugger_path),
        ProjectSubcommand::Config {} => project_config(),
        ProjectSubcommand::Bind {
            project_dir,
            pkg_name,
        } => project_bind(project_dir, pkg_name),
    }
}
